package edu.hawaii.duedates;

import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;

import edu.hawaii.duedates.libraries.HawaiiStatePublicLibraryQuery;
import edu.hawaii.duedates.libraries.UhManoaLibraryQuery;

/**
 * Main class for Due Dates project. Uses provided command line information to
 * log into specified lender websites and report information regarding due dates
 * of borrowed items.
 * 
 * @author Aric West
 * @author Daniel Tian
 */
public class DueDates {
  /** lender list. */
  public List<LenderQuery> lenderList = new ArrayList<LenderQuery>();
  /** calendar within date. */
  public Calendar withinDate = null;
  
  /**
   * Main method.
   * 
   * @param args
   *          Command line input including lender argument and log in
   *          information.
   * @throws Exception
   *           Throws exceptions propagated from subroutines and LenderQuery
   *           objects.
   */
  public static void main(String[] args) throws Exception {
    DueDates dueDates = new DueDates();
    CommandLineParser clparser = new CommandLineParser(args);
    String command;
    
    if (clparser.getOptions().size() == 0) {
      System.out.println("No valid arguments provided.");
      System.exit(0);
    }
    
    System.out.println("Please wait, retrieving library info...");
    
    for (DueDatesOption option : clparser.getOptions()) {
      command = option.getCommand();
      
      // -uhm flag
      if ("-uhm".equals(command)) {
        UhManoaLibraryQuery query = new UhManoaLibraryQuery();
        
        if (option.getParameters().size() == query.getExpectedNumberOfFields()) {
          if (query.logIn(option.getParameters())) {
            dueDates.lenderList.add(query);
          }
          else {
            System.out.println("Could not log into -uhm, check ID number and last name.");
          }
        }
        else {
         System.out.println("-uhm takes " + query.getExpectedNumberOfFields() + " parameters but" +
           " got " + option.getParameters().size() + " instead, ignoring -uhm option."); 
        }
      }
      // -hsl flag
      else if ("-hsl".equals(command)) {
        HawaiiStatePublicLibraryQuery query = new HawaiiStatePublicLibraryQuery();
        
        if (option.getParameters().size() == query.getExpectedNumberOfFields()) {
          if (query.logIn(option.getParameters())) {
            dueDates.lenderList.add(query);
          }
          else {
            System.out.println("Could not log into -hsl, check ID number and phone number.");
          }
        }
        else {
         System.out.println("-hsl takes " + query.getExpectedNumberOfFields() + " parameters but" +
           " got " + option.getParameters().size() + " instead, ignoring -hsl option."); 
        }
      }
      // -sort flag
      else if ("-sort".equals(command)) {
        if (option.getParameters().isEmpty() 
            || option.getParameterAt(0).equalsIgnoreCase("library")) {
          Collections.sort(dueDates.lenderList);
        }
        else if (option.getParameterAt(0).equalsIgnoreCase("duedate")) {
          for (LenderQuery lender : dueDates.lenderList) {
            lender.sort();
          }
        }
        else {
          System.out.println("Invalid sort type provided, use -sort [library | duedate].");
        }
      }
      // -within flag
      else if ("-within".equals(command)) {
        try {
          if (!option.getParameters().isEmpty()) {
            if (Integer.parseInt(option.getParameterAt(0)) < 0) {
              System.out.println("Error with -within, please enter a number larger than 0");
            }
            else {
              dueDates.withinDate = Calendar.getInstance();
              dueDates.withinDate.add(Calendar.DATE, Integer.parseInt(option.getParameterAt(0)));
            }
          }
        }
        catch (NumberFormatException e) {
          System.out.println("-within parameter is not an integer: " + option.getParameterAt(0));
        }
      }
      // Option catch-all.
      else {
        System.out.println("Invalid option: " + option.getCommand());
      }
    }
    
    if (dueDates.lenderList.isEmpty()) {
      System.out.println("No lenders queried.");
    }
    
    // parse borrowed items for all lenders
    for (LenderQuery lender : dueDates.lenderList) {
      lender.parseBorrowedItems();
    }
    
    // print borrowed items to console
    dueDates.printBorrowedItemsToConsole();
  }

  /**
   * Prints out the list of borrowed items.
   * 
   * @throws Exception
   *           throws an exception if there was a problem getting the list of
   *           borrowed items
   */
  private void printBorrowedItemsToConsole() throws Exception {
    List<BorrowedItem> itemList;
    int numOfDays = 0;
    boolean withinFlag = true;
    
    if (this.withinDate != null) {
      Calendar today = Calendar.getInstance();
      
      while (today.before(this.withinDate)) {
        today.add(Calendar.DATE, 1);
        numOfDays++;
      }
      
      System.out.println("Items due within " + numOfDays + " day(s):");
    }
    
    // Add a blank line between error messages and proper output 
    System.out.println();
    
    for (LenderQuery lender : this.lenderList) {
      itemList = lender.getItemList();
      
      System.out.println(lender.getLenderName() + ":");
      
      if (itemList.isEmpty()) {
        System.out.println("There are no items checked out.");
      }
      else {
        for (BorrowedItem item : itemList) {
          String name = item.getItemName();
          if (name.length() > 60) {
            name = name.substring(0, 59) + "...";
          }
          if (this.withinDate == null) {
            System.out.println("Due: " + item.getDueDateToString() + " | " + name);
            withinFlag = true;
          }
          else {
            if (item.getDueDate().before(this.withinDate)) {
              System.out.println("Due: " + item.getDueDateToString() + " | " + name);
              withinFlag = true;
            }
          }
        }
        
        if (!withinFlag) {
          System.out.println("There are no items due within the given time period.");
        }
      }
    }
  }
}